.static-analysis-base:
  extends:
    - .default-retry
    - .default-before_script
  stage: lint
  needs: []
  variables:
    SETUP_DB: "false"
    ENABLE_SPRING: "1"
    # Disable warnings in browserslist which can break on backports
    # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
    BROWSERSLIST_IGNORE_OLD_DATA: "true"
    GRAPHQL_SCHEMA_APOLLO_FILE: "tmp/tests/graphql/gitlab_schema_apollo.graphql"

update-static-analysis-cache:
  extends:
    - .static-analysis-base
    - .rubocop-job-cache-push
    - .shared:rules:update-cache
  stage: prepare
  script:
    # Silence cop offenses for rules with "grace period".
    # This will notify Slack if offenses were silenced.
    # For the moment we only cache `tmp/rubocop_cache` so we don't need to run all the tasks.
    - run_timed_command "fail_on_warnings bundle exec rake rubocop:check:graceful"

static-analysis:
  extends:
    - .static-analysis-base
    - .static-analysis-cache
    - .static-analysis:rules:static-analysis
  parallel: 2
  script:
    - yarn_install_script
    - fail_on_warnings scripts/static-analysis

static-analysis as-if-foss:
  extends:
    - static-analysis
    - .static-analysis:rules:static-analysis-as-if-foss
    - .as-if-foss

static-verification-with-database:
  extends:
    - .static-analysis-base
    - .rubocop-job-cache
    - .static-analysis:rules:static-verification-with-database
    - .use-pg13
  script:
    - bundle exec rake lint:static_verification_with_database
  variables:
    SETUP_DB: "true"

generate-apollo-graphql-schema:
  extends:
    - .static-analysis-base
    - .frontend:rules:default-frontend-jobs
  image:
    name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:apollo
    entrypoint: [""]
  needs: ['graphql-schema-dump']
  variables:
    USE_BUNDLE_INSTALL: "false"
  script:
    - apollo client:download-schema --config=config/apollo.config.js ${GRAPHQL_SCHEMA_APOLLO_FILE}
  artifacts:
    name: graphql-schema-apollo
    paths:
      - "${GRAPHQL_SCHEMA_APOLLO_FILE}"

generate-apollo-graphql-schema as-if-foss:
  extends:
    - generate-apollo-graphql-schema
    - .frontend:rules:eslint-as-if-foss
    - .as-if-foss
  needs: ['graphql-schema-dump as-if-foss']

eslint:
  extends:
    - .static-analysis-base
    - .yarn-cache
    - .frontend:rules:default-frontend-jobs
  needs: ['generate-apollo-graphql-schema']
  variables:
    USE_BUNDLE_INSTALL: "false"
  script:
    - yarn_install_script
    - run_timed_command "yarn run lint:eslint:all"

eslint as-if-foss:
  extends:
    - eslint
    - .frontend:rules:eslint-as-if-foss
    - .as-if-foss
  needs: ['generate-apollo-graphql-schema as-if-foss']

haml-lint:
  extends:
    - .static-analysis-base
    - .ruby-cache
    - .static-analysis:rules:haml-lint
  script:
    - run_timed_command "bundle exec haml-lint --parallel app/views"
  artifacts:
    expire_in: 31d
    when: always
    paths:
      - tmp/feature_flags/

haml-lint ee:
  extends:
    - "haml-lint"
    - .static-analysis:rules:haml-lint-ee
  script:
    - run_timed_command "bundle exec haml-lint --parallel ee/app/views"

rubocop:
  extends:
    - .static-analysis-base
    - .rubocop-job-cache
    - .static-analysis:rules:rubocop
  needs:
    - job: detect-tests
      optional: true
  variables:
    RUBOCOP_TARGET_FILES: "tmp/rubocop_target_files.txt"
  script:
    - |
      # For non-merge request, or when RUN_ALL_RUBOCOP is 'true', run all RuboCop rules
      if [ -z "${CI_MERGE_REQUEST_IID}" ] || [ "${RUN_ALL_RUBOCOP}" == "true" ]; then
        # Silence cop offenses for rules with "grace period".
        # We won't notify Slack if offenses were silenced to avoid frequent messages.
        # Job `update-static-analysis-cache` takes care of Slack notifications every 2 hours.
        unset CI_SLACK_WEBHOOK_URL
        run_timed_command "fail_on_warnings bundle exec rake rubocop:check:graceful"
      else
        cat "${RSPEC_CHANGED_FILES_PATH}" | ruby -e 'print $stdin.read.split(" ").select { |f| File.exist?(f) }.join(" ")' > "$RUBOCOP_TARGET_FILES"
        # Skip running RuboCop if there's no target files
        if [ -s "${RUBOCOP_TARGET_FILES}" ]; then
          run_timed_command "fail_on_warnings bundle exec rubocop --parallel --force-exclusion $(cat ${RUBOCOP_TARGET_FILES})"
        else
          echoinfo "Nothing interesting changed for RuboCop. Skipping."
        fi
      fi

qa:metadata-lint:
  extends:
    - .static-analysis-base
    - .static-analysis:rules:qa:metadata-lint
  before_script:
    - !reference [.default-before_script, before_script]
    - cd qa/
    - bundle_install_script
  script:
    - run_timed_command "bundle exec bin/qa Test::Instance::All http://localhost:3000 --test-metadata-only"
    - cd ..
    - run_timed_command "./scripts/qa/testcases-check qa/tmp/test-metadata.json"
    - run_timed_command "./scripts/qa/quarantine-types-check qa/tmp/test-metadata.json"
  variables:
    USE_BUNDLE_INSTALL: "false"
    SETUP_DB: "false"
    QA_EXPORT_TEST_METRICS: "false"
    # Disable warnings in browserslist which can break on backports
    # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
    BROWSERSLIST_IGNORE_OLD_DATA: "true"
  artifacts:
    expire_in: 31d
    when: always
    paths:
      - qa/tmp/

feature-flags-usage:
  extends:
    - .static-analysis-base
    - .rubocop-job-cache
    - .static-analysis:rules:rubocop
  script:
    # We need to disable the cache for this cop since it creates files under tmp/feature_flags/*.used,
    # the cache would prevent these files from being created.
    - run_timed_command "fail_on_warnings bundle exec rubocop --only Gitlab/MarkUsedFeatureFlags --cache false"
  artifacts:
    expire_in: 31d
    when: always
    paths:
      - tmp/feature_flags/

semgrep-appsec-custom-rules:
  stage: lint
  extends:
    - .semgrep-appsec-custom-rules:rules
  image: returntocorp/semgrep
  needs: []
  script:
    # Required to avoid a timeout https://github.com/returntocorp/semgrep/issues/5395
    - git fetch origin master
    # Include/exclude list isn't ideal https://github.com/returntocorp/semgrep/issues/5399
    - |
      semgrep ci --gitlab-sast --metrics off --config $CUSTOM_RULES_URL \
        --include app --include lib --include workhorse \
        --exclude '*_test.go' --exclude spec --exclude qa > gl-sast-report.json || true
  variables:
    CUSTOM_RULES_URL: https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/raw/main/appsec-pings/rules.yml
  artifacts:
    paths:
      - gl-sast-report.json

ping-appsec-for-sast-findings:
  stage: lint
  image: alpine:latest
  extends:
    - .ping-appsec-for-sast-findings:rules
  variables:
    # Project Access Token bot ID for /gitlab-com/gl-security/appsec/sast-custom-rules
    BOT_USER_ID: 13559989
  needs:
    - semgrep-appsec-custom-rules
  script:
    - apk add jq curl
    - scripts/process_custom_semgrep_results.sh
